﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;

namespace DbHelper.Implementation
{
    /// <summary>
    /// Implementação do Helper Db para o banco de dados Sql Server 2005.
    /// </summary>
    /// <remarks>Lucas Damiani</remarks>
    public class SqlDb : Db
    {
        #region Propriedades
        /// <summary>
        /// Consulta que traz a data/hora atual no banco de dados.
        /// </summary>
        /// <remarks>Lucas Damiani</remarks>
        public override string QueryDatetime
        {
            get { return QUERY_DATETIME; }
        }
        #endregion

        #region Constantes
        /// <summary>
        /// Consulta que traz a data/hora atual no banco de dados.
        /// </summary>
        /// <remarks>Lucas Damiani</remarks>
        private const string QUERY_DATETIME = "SELECT GETDATE()";
        #endregion

        #region Construtores
        /// <summary>
        /// Construtor default do helper para Sql Server.
        /// </summary>
        /// <remarks>Lucas Damiani</remarks>
        public SqlDb()
            : base()
        {
        }

        /// <summary>
        /// Construtor do helper para Sql Server. Utiliza o construtor da classe abstrata.
        /// </summary>
        /// <param name="connectionString">String de conexão.</param>
        /// <remarks>Lucas Damiani</remarks>
        public SqlDb(string connectionString)
            : base(connectionString)
        {
        }
        #endregion

        #region Métodos
        /// <summary>
        /// Método utilizado para buscar uma conexão com o banco de dados.
        /// </summary>
        /// <returns>Conexão com o banco de dados.</returns>
        /// <remarks>Lucas Damiani</remarks>
        public override DbConnection GetConnection()
        {
            return new SqlConnection(ConnectionString);
        }

        /// <summary>
        /// Método utilizado para buscar uma instância de DbParameter.
        /// </summary>
        /// <param name="name">Nome do parâmetro.</param>
        /// <param name="dbType">Tipo do parâmetro.</param>
        /// <param name="value">Valor que o parâmetro recebe. Se fornecido como "null", coloca o valor "DBNull.Value".</param>
        /// <returns>Instância de DbParameter de acordo com o banco de dados.</returns>
        /// <remarks>Lucas Damiani</remarks>
        public override DbParameter GetParameter(string name, DbType dbType, object value)
        {
            SqlParameter prm = new SqlParameter(name, dbType);
            if (value == null)
            {
                prm.Value = DBNull.Value;
            }
            else
            {
                prm.Value = value;
            }
            return prm;
        }

        

        /// <summary>
        /// Método utilizado para executar um comando de escrita no banco de dados.
        /// </summary>
        /// <param name="cmdType">Tipo do comando.</param>
        /// <param name="cmdText">Query ou nome da Stored Procedure.</param>
        /// <param name="cmdParms">Coleção de parâmetros SQL.</param>
        /// <returns>Inteiro com o resultado do método original.</returns>
        /// <remarks>Lucas Damiani</remarks>
        public override int ExecuteNonQuery(CommandType cmdType, string cmdText, List<DbParameter> cmdParms)
        {
            DbCommand cmd = new SqlCommand();
            using (DbConnection conn = new SqlConnection(ConnectionString))
            {
                try
                {
                    PrepareCommand(cmd, conn, null, cmdType, cmdText, cmdParms);
                    int val = cmd.ExecuteNonQuery();
                    cmd.Parameters.Clear();
                    return val;
                }
                catch
                {
                    conn.Close();
                    conn.Dispose();
                    throw;
                }
            }
        }

        /// <summary>
        /// Método utilizado para executar um comando de escrita no banco de dados, dentro de uma transação.
        /// </summary>
        /// <param name="trans">Transação corrente.</param>
        /// <param name="cmdType">Tipo do comando.</param>
        /// <param name="cmdText">Query ou nome da Stored Procedure.</param>
        /// <param name="cmdParms">Coleção de parâmetros SQL.</param>
        /// <returns>Inteiro com o resultado do método original.</returns>
        /// <remarks>Lucas Damiani</remarks>
        public override int ExecuteNonQuery(DbTransaction trans, CommandType cmdType, string cmdText, List<DbParameter> cmdParms)
        {
            DbCommand cmd = new SqlCommand();
            PrepareCommand(cmd, trans.Connection, trans, cmdType, cmdText, cmdParms);
            int val = cmd.ExecuteNonQuery();
            cmd.Parameters.Clear();
            return val;
        }

        /// <summary>
        /// Método utilizado para executar um comando de escrita no banco de dados.
        /// </summary>
        /// <param name="cmdType">Tipo do comando.</param>
        /// <param name="cmdText">Query ou nome da Stored Procedure.</param>
        /// <param name="cmdParms">Coleção de parâmetros SQL.</param>
        /// <returns>Comando SQL executado.</returns>
        /// <remarks>Lucas Damiani</remarks>
        public override DbCommand ExecuteNonQueryCmd(CommandType cmdType, string cmdText, List<DbParameter> cmdParms)
        {
            DbCommand cmd = new SqlCommand();
            using (DbConnection conn = new SqlConnection(ConnectionString))
            {
                try
                {
                    PrepareCommand(cmd, conn, null, cmdType, cmdText, cmdParms);
                    int val = cmd.ExecuteNonQuery();
                }
                catch
                {
                    conn.Close();
                    conn.Dispose();
                    throw;
                }
            }
            return cmd;
        }

        /// <summary>
        /// Método utilizado para executar um comando de escrita no banco de dados, dentro de uma transação.
        /// </summary>
        /// <param name="trans">Transação corrente.</param>
        /// <param name="cmdType">Tipo do comando.</param>
        /// <param name="cmdText">Query ou nome da Stored Procedure.</param>
        /// <param name="cmdParms">Coleção de parâmetros SQL.</param>
        /// <returns>Comando SQL executado.</returns>
        /// <remarks>Lucas Damiani</remarks>
        public override DbCommand ExecuteNonQueryCmd(DbTransaction trans, CommandType cmdType, string cmdText, List<DbParameter> cmdParms)
        {
            DbCommand cmd = new SqlCommand();
            PrepareCommand(cmd, trans.Connection, trans, cmdType, cmdText, cmdParms);
            int val = cmd.ExecuteNonQuery();
            return cmd;
        }

        /// <summary>
        /// Método utilizado para executar um comando de leitura no banco de dados.
        /// </summary>
        /// <param name="cmdType">Tipo do comando.</param>
        /// <param name="cmdText">Query ou nome da Stored Procedure.</param>
        /// <param name="cmdParms">Coleção de parâmetros SQL.</param>
        /// <returns>DbDataReader de retorno da consulta.</returns>
        /// <remarks>Lucas Damiani</remarks>
        public override DbDataReader ExecuteReader(CommandType cmdType, string cmdText, List<DbParameter> cmdParms)
        {
            DbDataReader dr = null;
            DbConnection conn = new SqlConnection(ConnectionString);
            try
            {
                DbCommand cmd = new SqlCommand();
                PrepareCommand(cmd, conn, null, cmdType, cmdText, cmdParms);
                dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
            }
            catch
            {
                conn.Close();
                conn.Dispose();
                throw;
            }
            return dr;
        }

        /// <summary>
        /// Método utilizado para executar um comando de leitura no banco de dados, dentro de uma transação.
        /// </summary>
        /// <param name="trans">Transação corrente.</param>
        /// <param name="cmdType">Tipo do comando.</param>
        /// <param name="cmdText">Query ou nome da Stored Procedure.</param>
        /// <param name="cmdParms">Coleção de parâmetros SQL.</param>
        /// <returns>DbDataReader de retorno da consulta.</returns>
        /// <remarks>Lucas Damiani</remarks>
        public override DbDataReader ExecuteReader(DbTransaction trans, CommandType cmdType, string cmdText, List<DbParameter> cmdParms)
        {
            DbDataReader dr = null;
            DbCommand cmd = new SqlCommand();
            PrepareCommand(cmd, trans.Connection, trans, cmdType, cmdText, cmdParms);
            dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
            return dr;
        }

        /// <summary>
        /// Método utilizado para executar um comando de leitura no banco de dados.
        /// </summary>
        /// <param name="cmdType">Tipo do comando.</param>
        /// <param name="cmdText">Query ou nome da Stored Procedure.</param>
        /// <param name="cmdParms">Coleção de parâmetros SQL.</param>
        /// <returns>DataSet de retorno da consulta.</returns>
        /// <remarks>Lucas Damiani</remarks>
        public override DataSet ExecuteReaderDs(CommandType cmdType, string cmdText, List<DbParameter> cmdParms)
        {
            DataSet ds = new DataSet();
            using (DbConnection conn = new SqlConnection(ConnectionString))
            {
                try
                {
                    DbCommand cmd = new SqlCommand();
                    PrepareCommand(cmd, conn, null, cmdType, cmdText, cmdParms);
                    DbDataAdapter da = new SqlDataAdapter((SqlCommand)cmd);
                    da.Fill(ds);
                    cmd.Parameters.Clear();
                }
                catch
                {
                    conn.Close();
                    conn.Dispose();
                    throw;
                }
            }
            return ds;
        }

        /// <summary>
        /// Método utilizado para executar um comando de leitura no banco de dados, dentro de uma transação.
        /// </summary>
        /// <param name="trans">Transação corrente.</param>
        /// <param name="cmdType">Tipo do comando.</param>
        /// <param name="cmdText">Query ou nome da Stored Procedure.</param>
        /// <param name="cmdParms">Coleção de parâmetros SQL.</param>
        /// <returns>DataSet de retorno da consulta.</returns>
        /// <remarks>Lucas Damiani</remarks>
        public override DataSet ExecuteReaderDs(DbTransaction trans, CommandType cmdType, string cmdText, List<DbParameter> cmdParms)
        {
            DataSet ds = new DataSet();
            DbCommand cmd = new SqlCommand();
            PrepareCommand(cmd, trans.Connection, trans, cmdType, cmdText, cmdParms);
            DbDataAdapter da = new SqlDataAdapter((SqlCommand)cmd);
            da.Fill(ds);
            cmd.Parameters.Clear();
            return ds;
        }

        /// <summary>
        /// Método utilizado para executar um comando de leitura no banco de dados.
        /// </summary>
        /// <param name="cmdType">Tipo do comando.</param>
        /// <param name="cmdText">Query ou nome da Stored Procedure.</param>
        /// <param name="cmdParms">Coleção de parâmetros SQL.</param>
        /// <returns>Objeto de retorno da consulta.</returns>
        /// <remarks>Lucas Damiani</remarks>
        public override object ExecuteScalar(CommandType cmdType, string cmdText, List<DbParameter> cmdParms)
        {
            object obj = new object();
            using (DbConnection conn = new SqlConnection(ConnectionString))
            {
                try
                {
                    DbCommand cmd = new SqlCommand();
                    PrepareCommand(cmd, conn, null, cmdType, cmdText, cmdParms);
                    obj = cmd.ExecuteScalar();
                    cmd.Parameters.Clear();
                }
                catch
                {
                    conn.Close();
                    conn.Dispose();
                    throw;
                }
            }
            return obj;
        }
        /// <summary>
        /// Método utilizado para executar um comando de leitura no banco de dados, dentro de uma transação.
        /// </summary>
        /// <param name="trans">Transação corrente.</param>
        /// <param name="cmdType">Tipo do comando.</param>
        /// <param name="cmdText">Query ou nome da Stored Procedure.</param>
        /// <param name="cmdParms">Coleção de parâmetros SQL.</param>
        /// <returns>Objeto de retorno da consulta.</returns>
        /// <remarks>Lucas Damiani</remarks>
        public override object ExecuteScalar(DbTransaction trans, CommandType cmdType, string cmdText, List<DbParameter> cmdParms)
        {
            DbCommand cmd = new SqlCommand();
            PrepareCommand(cmd, trans.Connection, trans, cmdType, cmdText, cmdParms);
            object obj = cmd.ExecuteScalar();
            cmd.Parameters.Clear();
            return obj;
        }
        #endregion
    }
}
